package com.jzo2o.foundations.service.impl;

import cn.hutool.json.JSONUtil;
import com.jzo2o.api.foundations.dto.response.ServeAggregationResDTO;
import com.jzo2o.common.utils.StringUtils;
import jodd.io.StreamUtil;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.mapper.*;
import com.jzo2o.foundations.model.domain.*;
import com.jzo2o.foundations.model.dto.request.ServePageQueryReqDTO;
import com.jzo2o.foundations.model.dto.request.ServeUpsertReqDTO;
import com.jzo2o.foundations.model.dto.response.*;
import com.jzo2o.foundations.service.IServeService;
import com.jzo2o.mysql.utils.PageHelperUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务同步表 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-10
 */
@Service
public class ServeServiceImpl extends ServiceImpl<ServeMapper, Serve> implements IServeService {

    @Autowired
    private ServeItemMapper serveItemMapper;
    @Autowired
    private ServeMapper serveMapper;
    @Autowired
    private RegionServiceImpl regionService;
    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private ServeTypeMapper serveTypeMapper;

    @Autowired
    private ServeSyncMapper serveSyncMapper;

    @Autowired
    private RestHighLevelClient client;

    /**
     * 搜索服务
     * @param cityCode
     * @param keyword
     * @param serveTypeId
     * @return
     */
    @Override
    public List<ServeSimpleResDTO> search(Long cityCode, String keyword, String serveTypeId) {
        //1.创建请求
        SearchRequest request = new SearchRequest("");
        //2.封装参数


        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        boolQuery.must(QueryBuilders.termQuery("city_code", cityCode));

        if(StringUtils.isNotEmpty(keyword))
        {
            boolQuery.must(QueryBuilders.multiMatchQuery(keyword,"serve_item_name", "serve_type_name"));
        }

        if(StringUtils.isNotEmpty(serveTypeId))
        {
            boolQuery.must(QueryBuilders.termQuery("serve_type_id", serveTypeId));
        }

        request.source().query();
        request.source().sort("serve_item_sort_num", SortOrder.ASC);
        //3.发送请求
        SearchResponse response=null;
        try {
             response = client.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        //4.解析结果并返回
        long total = response.getHits().getTotalHits().value;
        if(total==0)
        {
            return List.of();

        }

      return  Arrays.stream(response.getHits().getHits())
                .map(e -> JSONUtil.toBean(e.getSourceAsString(), ServeSimpleResDTO.class))
                .collect(Collectors.toList());

    }


    @Override
    public ServeAggregationResDTO findServeDetailById(Long id) {
        return baseMapper.findServeDetailById(id);
    }


    /**
     * 区域服务分页查询
     *
     * @param servePageQueryReqDTO
     * @return 分页结果
     */
    @Override
    public PageResult<ServeResDTO> findPage(ServePageQueryReqDTO servePageQueryReqDTO) {
        return PageHelperUtils.selectPage(servePageQueryReqDTO,
                () -> baseMapper.queryList(servePageQueryReqDTO.getRegionId()));
    }


    /**
     * 区域服务新增
     *
     * @param dtoList
     */
    @Transactional
    @Override
    public void add(List<ServeUpsertReqDTO> dtoList) {
        //获取区域id,服务项目id以及价格
        for (ServeUpsertReqDTO dto : dtoList) {
            //1.判断服务项目是否已经被启用,就是状态是否是2
            ServeItem serveItem = serveItemMapper.selectById(dto.getServeItemId());
            if (ObjectUtils.isNull(serveItem) || serveItem.getActiveStatus() != 2) {
                throw new ForbiddenOperationException("服务项目添加失败");
            }
            //2.判断同一个区域是否已经存在相同的服务项目,一个区域一个服务项目
            //根据区域id和服务项目id查询,统计有多少条满足这两个条件的数据  大于0说明已经存在
            Integer n = serveMapper.selectCount(
                    Wrappers.<Serve>lambdaQuery()
                            .eq(Serve::getRegionId, dto.getRegionId())
                            .eq(Serve::getServeItemId, dto.getServeItemId()));
            if (n > 0) {
                throw new ForbiddenOperationException("服务项目添加失败,当前项目已经存在");
            }

            //3.插入
            //区域id
            //服务id
            //价格
            //城市编码
            //其他的有默认值和自动填充

            Serve serve = BeanUtils.copyBean(dto, Serve.class);

            //根据区域id查询城市编码
            Region region = regionService.getById(dto.getRegionId());
            serve.setCityCode(region.getCityCode());
            serveMapper.insert(serve);
        }
    }

    /**
     * 区域服务删除
     *
     * @param id 区域服务id
     */
    @Override
    public void deleteById(Long id) {
        //首先服务状态必须是草稿状态才能删除 也就是0
        Serve serve = baseMapper.selectById(id);
        if (ObjectUtils.isNull(serve) || serve.getSaleStatus() != 0) {
            throw new ForbiddenOperationException("服务删除失败");
        }
        baseMapper.deleteById(id);
    }

    @Transactional
    @Override
    public void OnSate(Long id) {
        //修改要求
        // 1) 区域服务当前非上架状态
        Serve serve = baseMapper.selectById(id);
        if (ObjectUtils.isNull() || serve.getSaleStatus() == 2) {
            throw new ForbiddenOperationException("服务上架失败");
        }
        // 2) 服务项目是启用状态
        ServeItem serveItem = serveItemMapper.selectById(serve.getServeItemId());
        if (ObjectUtils.isNull(serveItem) || serveItem.getActiveStatus() != 2) {
            throw new ForbiddenOperationException("服务项目未启用");
        }
        // 3) 执行修改
        serve.setSaleStatus(2);
        baseMapper.updateById(serve);

        addServeSync(id);
    }


    /**
     * 新增服务同步数据
     *
     * @param serveId 服务id
     */
    private void addServeSync(Long serveId) {
        //服务信息
        Serve serve = baseMapper.selectById(serveId);
        //区域信息
        Region region = regionMapper.selectById(serve.getRegionId());
        //服务项信息
        ServeItem serveItem = serveItemMapper.selectById(serve.getServeItemId());
        //服务类型
        ServeType serveType = serveTypeMapper.selectById(serveItem.getServeTypeId());

        ServeSync serveSync = new ServeSync();
        serveSync.setServeTypeId(serveType.getId());
        serveSync.setServeTypeName(serveType.getName());
        serveSync.setServeTypeIcon(serveType.getServeTypeIcon());
        serveSync.setServeTypeImg(serveType.getImg());
        serveSync.setServeTypeSortNum(serveType.getSortNum());

        serveSync.setServeItemId(serveItem.getId());
        serveSync.setServeItemIcon(serveItem.getServeItemIcon());
        serveSync.setServeItemName(serveItem.getName());
        serveSync.setServeItemImg(serveItem.getImg());
        serveSync.setServeItemSortNum(serveItem.getSortNum());
        serveSync.setUnit(serveItem.getUnit());
        serveSync.setDetailImg(serveItem.getDetailImg());
        serveSync.setPrice(serve.getPrice());

        serveSync.setCityCode(region.getCityCode());
        serveSync.setId(serve.getId());
        serveSync.setIsHot(serve.getIsHot());
        serveSyncMapper.insert(serveSync);
    }

    /**
     * 区域服务下架
     *
     * @param id
     */
    @Override
    public void offSale(Long id) {
        //判断当前区域服务是不是上架状态
        Serve serve = baseMapper.selectById(id);
        if (ObjectUtils.isNull(serve) || serve.getSaleStatus() != 2) {
            throw new ForbiddenOperationException("服务下架失败");
        }
        //执行修改
        serve.setSaleStatus(1);
        baseMapper.updateById(serve);
    }

    @Override
    public void OnHot(Long id) {
        //判断当前的区域服务的热门状态是否是启用状态
        Serve serve = baseMapper.selectById(id);
        if (ObjectUtils.isNull(serve) || serve.getIsHot() == 1) {
            throw new ForbiddenOperationException("区域服务热门状态设置失败");
        }
        serve.setIsHot(1);
        //设置当前时间的毫秒值
        serve.setHotTimeStamp(System.currentTimeMillis());
        baseMapper.updateById(serve);
    }


    /**
     * 区域服务取消热门
     * @param id
     */
    @Override
    public void offHot(Long id) {
        //判断当前的区域服务的热门状态是否是启用状态
        Serve serve = baseMapper.selectById(id);
        if (ObjectUtils.isNull(serve) || serve.getIsHot() == 0) {
            throw new ForbiddenOperationException("区域服务热门状态取消失败");
        }
        serve.setIsHot(0);
        serve.setHotTimeStamp(System.currentTimeMillis());
        baseMapper.updateById(serve);


        //删除服务同步数据
        serveSyncMapper.deleteById(id);
    }

    @Caching(cacheable = {
            @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key = "#regionId",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES,unless = "#result.size()>0"),//如果查询到的这个集合大小 小于等于0  缓存30分钟 (就是没有查到数据的时候就缓存30分钟)
            @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key = "#regionId",cacheManager = RedisConstants.CacheManager.FOREVER,unless = "#result.size()==0")//如果查询到的集合大小 大于0  缓存永久
    })
    @Override
    public List<ServeCategoryResDTO> firstPageServeList(Long regionId) {
        //先判断该区域是否存在
        Region region = regionService.getById(regionId);
        if (ObjectUtils.isNull(region) || region.getActiveStatus() != 2) {
            return CollUtils.emptyList();
        }

        //2.查询指定区域下 上架的的服务类型和项目信息
        List<ServeCategoryResDTO> list = baseMapper.findList(regionId);
        if (CollUtils.isEmpty(list)) {
            return CollUtils.emptyList();
        }

        //3.截取
        list = CollUtils.sub(list, 0, Math.min(list.size(), 2));

        list.forEach(e -> {
            List<ServeSimpleResDTO> list1 = e.getServeResDTOList();
            list1 = CollUtils.sub(list1, 0, Math.min(list1.size(), 4));
            e.setServeResDTOList(list1);
        });

        return list;
    }

    /**
     * 精选推荐
     *
     * @param regionId
     * @return
     */
    @Caching(cacheable = {
            @Cacheable(value = RedisConstants.CacheName.HOT_SERVE,key = "#regionId",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES,unless = "#result.size()>0"),//如果查询到的这个集合大小 小于等于0  缓存30分钟 (就是没有查到数据的时候就缓存30分钟)
            @Cacheable(value = RedisConstants.CacheName.HOT_SERVE,key = "#regionId",cacheManager = RedisConstants.CacheManager.FOREVER,unless = "#result.size()==0")//如果查询到的集合大小 大于0  缓存永久
    })    @Override
    public List<ServeAggregationSimpleResDTO> hotServeList(Long regionId) {
        //先判断该区域是否存在
        Region region = regionService.getById(regionId);
        if (ObjectUtils.isNull(region) || region.getActiveStatus() != 2) {
            return CollUtils.emptyList();
        }
        //获取响应数据
        List<ServeAggregationSimpleResDTO> list = baseMapper.findHotList(regionId);

        return list;
    }

    /**
     * 查询服务详情
     *
     * @param id
     * @return
     */
    @Override
    public ServeAggregationSimpleResDTO fingById(Long id) {
        /*
        * - 分步查询：效率比较低，但是sql书写简单，产生的笛卡尔积较小
        我们本功能采用第二种方式来实现，即：
1. 先根据服务id从服务表中查询服务信息
2. 再根据服务项目id从服务项表中查询服务项信息
3. 最后将两部分结果组装在一起进行返回*/

        Serve serve = serveMapper.selectById(id);
        if (ObjectUtils.isNull(serve)) {
            throw new ForbiddenOperationException("服务详情查询失败");
        }


        ServeItem serveItem = serveItemMapper.selectById(serve.getServeItemId());
        if (ObjectUtils.isNull(serveItem)) {
            throw new ForbiddenOperationException("服务项详情查询失败");
        }

        ServeAggregationSimpleResDTO dto =new ServeAggregationSimpleResDTO();
            dto.setCityCode(serve.getCityCode());
            dto.setPrice(serve.getPrice());
            dto.setId(serve.getId());
            dto.setServeItemId(serveItem.getId());
            dto.setServeItemName(serveItem.getName());
            dto.setServeItemImg(serveItem.getImg());
            dto.setUnit(serveItem.getUnit());
            dto.setDetailImg(serveItem.getDetailImg());
            return dto;


        }

    @Override
    public List<ServeAggregationTypeSimpleResDTO> serveTypeList(Long regionId) {

        //先判断该区域是否存在
        Region region = regionService.getById(regionId);
        if (ObjectUtils.isNull(region) || region.getActiveStatus() != 2) {
            return CollUtils.emptyList();
        }

        return baseMapper.findServeTypeListByRegionId(regionId);

    }



}

















